package org.medusa.buffer;

public class RingBuffer extends Buffer {
	
	protected byte[] buffer = null;
	protected int buffer_size;
	protected int read_offset;
	protected int write_offset;
	protected int expand_size;
	
	public RingBuffer(int capacity, int expand_size) {
		super();
		this.buffer = new byte[capacity];
		this.buffer_size = capacity;
		this.read_offset = 0;
		this.write_offset = 0;
		this.expand_size = expand_size;
	}
	
	//clear
	@Override
	public void Clear() {
		this.read_offset = this.write_offset = 0;
	}

	@Override
	public boolean IsFull() {
		return (((this.write_offset + 1) %
                this.buffer_size) == this.read_offset);
	}
	
	@Override
	public boolean IsEmpty() {
		return (this.read_offset == this.write_offset);
	}
	
	// size
	@Override
	public int BufferSize() {
		return this.buffer_size;
	}
	
	public int ExpandSize() {
        return this.expand_size;
    }
	
	@Override
	public int DataSize() {
		if (this.write_offset == this.read_offset)
			return 0;

		return (this.write_offset > this.read_offset) ? (this.write_offset - this.read_offset)
				: (this.buffer_size - this.read_offset + this.write_offset);
	}

	@Override
	public int FreeSize() {
		if (this.write_offset == this.read_offset)
			return this.buffer_size;

		return (this.write_offset > this.read_offset) ? (this.buffer_size
				- this.write_offset + this.read_offset)
				: (this.read_offset - this.write_offset);
	}

	@Override
	public int LineDataSize() {
		if (this.write_offset == this.read_offset)
			return 0;

		return (this.write_offset > this.read_offset) ? (this.write_offset - this.read_offset)
				: (this.buffer_size - this.read_offset);
	}

	@Override
	public int LineFreeSize() {
		if (this.write_offset == this.read_offset)
			return this.buffer_size - this.write_offset;

		return (this.write_offset > this.read_offset) ? (this.buffer_size - this.write_offset)
				: (this.read_offset - this.write_offset);
	}
	
	// Byte
		@Override
		public byte ReadInt8() {
			byte ret = this.buffer[this.read_offset];
			this.add_read_offset(1);
			return ret;
		}

		@Override
		public void WriteInt8(byte val) {
			if(this.IsFull()) {
	            int new_buff_size = this.buffer_size + this.expand_size;
				byte []new_buffer = new byte[new_buff_size];
	            //byte []old_buffer = this.buffer;
	            //size_t data_size = this.DataSize();
	            int size=0;
	            while(!this.IsEmpty()) {
	                new_buffer[size] = this.ReadInt8();
	                size++;
	            }
				this.buffer = new_buffer;
				this.buffer_size = new_buff_size;
	            this.read_offset = 0;
	            this.write_offset = size;
	        }
			
			this.buffer[this.write_offset] = val;
			this.add_write_offset(1);
		}

		// offset
		protected int add_read_offset(int offset) {
			this.read_offset = ((this.read_offset+offset) % this.buffer_size);

			return this.read_offset;
		}

		protected int add_write_offset(int offset) {
			this.write_offset = ((this.write_offset+offset) % this.buffer_size);

			return this.write_offset;
		}

}
